package com.example.springbootdemo.filter;

import com.alibaba.fastjson.JSONObject;
import com.example.springbootdemo.exception.BusinessResponseEnum;
import com.example.springbootdemo.bean.response.ResponseInfo;
import com.example.springbootdemo.util.JwtTokenUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 对/login的POST请求坐拦截，校验表单中用户名，密码
 * @author H
 * @time 2022/1/31 16:45
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

   private final AuthenticationManager authenticationManager;
   private final RedisTemplate redisTemplate;

    public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate) {
        this.authenticationManager = authenticationManager;
        this.redisTemplate = redisTemplate;
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
    }

    /**
     * 获取表单提交的用户名和密码
     * @param request request
     * @param response response
     * @return Authentication
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
    }

    /**
     * 认证成功调用的方法
     * @param request request
     * @param response response
     * @param chain chain
     * @param authResult authResult
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        org.springframework.security.core.userdetails.User user = (org.springframework.security.core.userdetails.User) authResult.getPrincipal();
        // 根据用户名生成token
        String token = JwtTokenUtils.generateToken(user.getUsername());
        // 把用户名和用户权限列表放到redis中
        redisTemplate.opsForValue().set(user.getUsername(), user.getAuthorities());

        response.setContentType("application/json;charset=utf-8");
        Map<String, String> result = new HashMap<>();
        result.put("token", token);
        ResponseInfo responseInfo = ResponseInfo.success(result);
        response.getWriter().write(JSONObject.toJSONString(responseInfo));
    }

    /**
     * 认证失败调用的方法
     * @param request request
     * @param response response
     * @param failed failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(JSONObject.toJSONString(ResponseInfo.fail(BusinessResponseEnum.LOGIN_FAIL)));
    }
}
